﻿using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using YAXLib;
using RaytracerLib.Layers.Interpolators;
using RaytracerLib.Layers.OverlayCorrectors;
using RaytracerLib.Cache;

namespace RaytracerLib.Layers
{
    public class ValueArrayFloatFile : ValueArrayFloat, ICacheable
    {
        private class CacheData
        {
            public float[,] Data;
            public int Width;
            public int Height;
        }

        [YAXNode]
        public string FileName { get; private set; }

        private CacheData m_cache_data;

        public ValueArrayFloatFile(string a_fileName,
            OverlayMethod a_overlayMethod = OverlayMethod.Overlap,
            InterpolationMethod a_interpolationMethod = InterpolationMethod.Bilinear)
            : base(a_overlayMethod, a_interpolationMethod)
        {
            FileName = a_fileName;
            Load();
        }

        ~ValueArrayFloatFile()
        {
            if (m_values != null)
                Unbind();
        }

        private void Load()
        {
            if (m_values == null)
            {
                Action loader = () =>
                {
                    string file_name = FileName;

                    if (!Path.IsPathRooted(file_name))
                        file_name = PathResolver.GetTexturePath(file_name);

                    using (Bitmap bmp = new Bitmap(file_name))
                        Create(bmp);

                    m_cache_data = new CacheData()
                    {
                        Width = Width,
                        Height = Height,
                        Data = m_values
                    };
                };

                m_cache_data = CacheManager.GetOrLoad<CacheData>(this, loader);

                m_values = m_cache_data.Data;
                Width = m_cache_data.Width;
                Height = m_cache_data.Height;
            }
        }

        public override void SetValue(int a_x, int a_y, double a_value)
        {
            throw new InvalidOperationException();
        }

        public override void RenderEnd(bool a_all)
        {
            base.RenderEnd(a_all);

            Unbind();
        }

        private void Unbind()
        {
            CacheManager.Unbind(this);

            m_values = null;
            m_cache_data = null;
        }

        public override void RenderStart(RenderStartPhase a_phase)
        {
            base.RenderStart(a_phase);

            if (a_phase == RenderStartPhase.PrepareObjectToRender)
                Load();
        }

        public override string ToString()
        {
            return String.Format("{0}; Width: {1}; Height: {2}; FileName: {3}",
                GetType().Name, Width, Height, FileName);
        }

        public override bool EqualsContent(ValueArrayFloat a_ar)
        {
            if (a_ar is ValueArrayFloatFile)
            {
                ValueArrayFloatFile ar = a_ar as ValueArrayFloatFile;
                return (ar.FileName == FileName);
            }
            else
                return base.EqualsContent(a_ar);
        }

        public override bool Equals(object a_obj)
        {
            if (Object.ReferenceEquals(a_obj, this))
                return true;

            ValueArrayFloatFile ar = a_obj as ValueArrayFloatFile;
            if (ar != null)
            {
                if (FileName != ar.FileName)
                    return false;
            }

            if (!base.Equals(a_obj))
                return false;

            return true;
        }

        public override int GetHashCode()
        {
            return base.GetHashCode() ^ FileName.GetHashCode();
        }

        public int MemoryUsage
        {
            get
            {
                return Width * Height * sizeof(float);
            }
        }

        public object Data
        {
            get
            {
                return m_cache_data;
            }
        }
    }
}